package com.sias.beanpostprocessor;

import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.env.StandardEnvironment;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author 吴文杰
 * @version 1.0
 * @since 2023/5/31 22:45
 */
// AutowiredAnnotationBeanPostProcessor 运行分析
@SuppressWarnings("all")
public class DigInAutowired {
  public static void main(String[] args) throws Throwable {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    beanFactory.registerSingleton("bean2", new Bean2()); // 创建过程， 不会走依赖注入和初始化
    beanFactory.registerSingleton("bean3", new Bean3());
    beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); //@Value
    beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); //${} 解析器

    // 1.查找哪些属性、方法加了@Autowired 这称之为InjectionMetadata
    AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
    processor.setBeanFactory(beanFactory);
    Bean1 bean1 = new Bean1();
    // System.out.println(bean1);
    // processor.postProcessProperties(null,bean1,"bean1"); //执行依赖注入 @Autowired @Value
    // System.out.println(bean1);
    Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
    findAutowiringMetadata.setAccessible(true);
    InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);// 获取bean1上加了@AutoWired @Value  的成员变量 方法参数信息
    System.out.println(metadata.toString());


    // 2.调用InjectionMetadata 来进行依赖注入，注入时按类型查找值
    metadata.inject(bean1, "bean1", null);
    System.out.println(bean1);
    // 3.如何类型查找
    Field bean3 = Bean1.class.getDeclaredField("bean3");
    DependencyDescriptor descriptor = new DependencyDescriptor(bean3, false);
    Object o = beanFactory.doResolveDependency(descriptor, null, null, null);
    System.out.println(o);

    Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
    DependencyDescriptor descriptor1 = new DependencyDescriptor(new MethodParameter(setBean2,0),false);
    Object o1 = beanFactory.doResolveDependency(descriptor1, null, null, null);
    System.out.println(o1);

    Method setHome = Bean1.class.getDeclaredMethod("setName", String.class);
    DependencyDescriptor descriptor2 = new DependencyDescriptor(new MethodParameter(setHome,0),true);
    Object o2 = beanFactory.doResolveDependency(descriptor2, null, null, null);
    System.out.println(o2);

  }
}
